#include "threadPool.h"
// 定义命令类型
#include "tlv.h"


int send_all(int sockfd,const void *buf,size_t len){
    size_t total=0;
    const char*p=(const char*)buf;
    while(total<len){
        ssize_t n=send(sockfd,p+total,len-total,0);
        total+=n;
    }
    return 0;
}
//发送tlv
int sendTlv(int sockfd,TLV_t *tlv){
    char buf[TLV_HEADER_SIZE];
    buf[0]=tlv->type;
    memcpy(buf+1,&tlv->seq,4);
    memcpy(buf+5,&tlv->length,4);
    if(send_all(sockfd,buf,sizeof(buf))!=0){
        return -1;
    }
    if(tlv->length>0){
        return send_all(sockfd,tlv->value,tlv->length);
    }
    return 0;
}

int recv_all(int sockfd,void *buf,size_t len){
    size_t total=0;
    char *p=(char*)buf;
    while(total<len){
        ssize_t n=recv(sockfd,p+total,len-total,0);
        total+=n;
    }
    return 0;
}
//计算hash
int hash_count(const char *filename,char *hash_str){
    SHA256_CTX ctx;
    SHA256_Init(&ctx);
    char buf[4096];
    int fd=open(filename,O_RDWR);
    while(1){
        bzero(buf,sizeof(buf));
        ssize_t sret=read(fd,buf,sizeof(buf));
        SHA256_Update(&ctx,buf,sret);
        if(sret==0){
            break;
        }
    }
    unsigned char sha[32];
    SHA256_Final(sha,&ctx);
    for(int i=0;i<32;i++){
        char temp[3]={0};
        sprintf(temp,"%02x",sha[i]);
        strcat(hash_str,temp);
    }
    return 0;
}

//接收tlv
int recvTlv(int sockfd,TLV_t* tlv){
    char buf[TLV_HEADER_SIZE];
    recv_all(sockfd,buf,sizeof(buf));
    tlv->type=buf[0];
    memcpy(&tlv->seq,buf+1,4);
    memcpy(&tlv->length,buf+5,4);
    if(tlv->length>0){
        recv_all(sockfd,tlv->value,tlv->length);
    }
    return 0;
}
int recvFile(int netfd,TLV_t*tlv,pathStack_t *cur,MYSQL*mysql,fileMetaData_t*meta){
     // 处理远程路径
    char remote_path[1024] = {0};
    strncpy(remote_path, tlv->value, tlv->length);
    remote_path[tlv->length] = '\0';

    printf("接收到上传请求, 目标路径: %s\n", remote_path);
    
    // 提取文件名（路径的最后一部分）
    char *filename = strrchr(remote_path, '/');
    if (!filename) {
        // 如果没有斜杠，整个字符串作为文件名
        filename = remote_path;
    } else {
        // 跳过斜杠获取文件名
        filename++;
    }
    
    printf("实际文件名: %s\n", filename);
    
    // 文件将保存在当前工作目录
    char cwd[PATH_MAX] = {0};
    getcwd(cwd, sizeof(cwd));
    
    // 构建完整文件路径
    char full_path[PATH_MAX] = {0};
    snprintf(full_path, sizeof(full_path), "%s/%s", cwd, filename);
    printf("创建文件: %s\n", full_path);

    TLV_t file_header;//接收文件大小
    recvTlv(netfd,&file_header);
    if(file_header.type!=CMD_FILE_START){
        return -1;
    }
    uint32_t file_size;
    memcpy(&file_size,file_header.value,file_header.length);
    int fd=open(full_path,O_WRONLY|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fd,-1,"open");
    file_size = ntohl(file_size);
    uint64_t total_receive=0;
    char buff[4096];
    while(total_receive<file_size){
        size_t to_receive;
        size_t remaining=file_size-total_receive;
        if (remaining > sizeof(buff)) {
            to_receive = sizeof(buff);
        } else {
            to_receive = remaining;
        }
        ssize_t n=recv(netfd,buff,to_receive,0);

        write(fd,buff,n);
        total_receive+=n;
        double progress = (double)total_receive / file_size * 100;
        printf("Progress: %.1f%%\r", progress);
        fflush(stdout);
    }
    TLV_t end_tlv;//接收文件的hash值
    memset(&end_tlv, 0, sizeof(TLV_t));
    recvTlv(netfd, &end_tlv);
    if(end_tlv.type==CMD_FILE_END){
        printf("\n文件上传结束\n");
    }
    printf("\n文件上传 %s: %ld/%d 字节\n",
           (total_receive == file_size) ? "完成" : "失败",
           total_receive, file_size);
    printf("哈希:%s\n",end_tlv.value);
    strncpy(meta->hash,end_tlv.value,sizeof(meta->hash));
    meta->file_type=0;
    strncpy(meta->filename,full_path,sizeof(meta->filename));
    strncpy(meta->path,remote_path,sizeof(meta->path));
    char hash_str[65]={0};
    hash_count(full_path,hash_str);//校验hash
    if(strcmp(meta->hash,hash_str)!=0){
        printf("经过校验，hash值不匹配,请重传\n");
        unlink(full_path);//删除文件
        close(fd);
        return -1;
    }
    printf("校验后,hash值一致\n");
    pri_mkdir(false, meta,cur);
    close(fd);
    return 0;

}
//发送客户端需要的文件
int getFile(int netfd,TLV_t*tlv,pathStack_t *cur){
      char real_path[1024]={0};
      strncpy(real_path,tlv->value,tlv->length);
      real_path[tlv->length]='\0';


   
     // 计算文件哈希
    char file_hash[65] = {0};
    hash_count(real_path, file_hash);

    struct stat st;
    int fd = open(real_path, O_RDONLY);
    ERROR_CHECK(fd,-1,"open");
    fstat(fd,&st);
    uint32_t file_size = st.st_size;
    uint32_t net_file_size = htonl(file_size);
    TLV_t start_tlv;
    memset(&start_tlv,0,sizeof(TLV_t));
    start_tlv.type = CMD_FILE_START;
    printf("filesize=%ld\n",st.st_size);
    memcpy(start_tlv.value, &net_file_size, sizeof(net_file_size));
    start_tlv.length = sizeof(net_file_size);
    printf("Sending file: %s (%u bytes)\n", real_path, file_size);
    off_t total_sent = 0;
    off_t offset = 0;
    sendTlv(netfd,&start_tlv);
    while (total_sent < file_size) {
        ssize_t sent = sendfile(netfd, fd, &offset, file_size - total_sent);
        total_sent += sent;
        double progress = (double)total_sent / file_size * 100;
        printf("Get progress: %.1f%%\r", progress);
        fflush(stdout);
    }
    TLV_t end_tlv;
    memset(&end_tlv, 0, sizeof(TLV_t));
    end_tlv.type = CMD_FILE_END;
    end_tlv.length = sizeof(file_hash);
    strncpy(end_tlv.value, file_hash, sizeof(end_tlv.value) - 1);
    printf("file_hash=%s\n",end_tlv.value);

    sendTlv(netfd, &end_tlv);
    printf("\n文件发送 %s: %ld/%d 字节\n",
           (total_sent == file_size) ? "完成" : "失败",
           total_sent, file_size);

    close(fd);
   
   
    return 0;
}
//检测文件的hash
int check_file_hash(int netfd,TLV_t*tlv,MYSQL*mysql){
    TLV_t response;
    memset(&response,0,sizeof(TLV_t));
    char sql[128];
    snprintf(sql, sizeof(sql),
                  "SELECT hash FROM userfile WHERE hash='%s'",
                  tlv->value);//将value的值拼接到字符串中
    int qret=mysql_query(mysql,sql);
    if (qret != 0) {
    fprintf(stderr, "查询失败:%s\n", mysql_error(mysql));
    return 0;
    }
    MYSQL_RES *result = mysql_store_result(mysql);
    if(result!=NULL){
        if(mysql_num_rows(result)>0){
        response.type=CMD_FILE_EXISTS;
        sendTlv(netfd,&response);
        printf("已有重复文件\n");
        mysql_free_result(result);
        return -1;
        }
        mysql_free_result(result);
        response.type=CMD_RESPONSE;
        sendTlv(netfd,&response);
        printf("无重复文件\n");
    }
        return 0;
}

